﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using SiGeSIB.Data.Common;

namespace SiGeSIB.GUI.Common
{
    public abstract partial class FGenericEditor<T> : ConflictableForm, IStateModifier
    {
        public FGenericEditor(EFormState formState, int entityId)
        {
            InitializeComponent();

			#region ToolStrip Step
			uEditDefaultToolStrip.ExitClicked += new EventHandler(uEditDefaultToolStrip_ExitClicked);
			uEditDefaultToolStrip.EditClicked += new EventHandler(uEditDefaultToolStrip_EditClicked);
			uEditDefaultToolStrip.SaveClicked += new EventHandler(uEditDefaultToolStrip_SaveClicked);
			uEditDefaultToolStrip.CancelClicked += new EventHandler(uEditDefaultToolStrip_CancelClicked); 
			#endregion
			
			#region Controller
			_Controller = new FormController(defaultStatusBar1);
			_Controller.BusyStateChanged += new EventHandler(_Controler_BusyStateChanged);
			_Controller.DisplayIdleMessage(_IdleMessage);
			#endregion

			#region MembersStep
			_FieldsToLock = new List<object>(uEditDefaultToolStrip.FieldsToLock);
			_Id = entityId;
			FormState = InitialState = formState; 
			#endregion
        }

        #region Attributes
		protected T _CurrentEntity;
		protected bool _AlreadyLoaded;
		private List<object> _FieldsToLock;
        #endregion
		#region Properties
		protected EFormState _FormState;
		protected FormController _Controller;
		protected int _Id;
		protected string _IdleMessage;
		protected EFormState InitialState;
		public DialogResult DialogResult = DialogResult.Cancel;
		protected Manager _Manager { get { return Manager.Instance; } }
		protected EFormState FormState
		{
			get
			{
				return _FormState;
			}
			set
			{
				uEditDefaultToolStrip.FormState = value;
			
				if (!value.Equals(_FormState))
				{
					_FormState = value;
					_ChangeFieldsLock();
				}
			}
		}
		protected List<object> FieldsToLock
		{
			get
			{
				return _FieldsToLock;
			}
			set
			{
				if (value != null)
				{
					_FieldsToLock = (value.Union(uEditDefaultToolStrip.FieldsToLock)).ToList();
				}
				else
				{
					_FieldsToLock = uEditDefaultToolStrip.FieldsToLock;
				}
			}
		}
		protected abstract bool HasEditPermission { get; }
		#endregion

		#region Methods
		#region General
		protected virtual void _RefreshConditionalLocks() { }
		private void _RefreshUIState()
		{
			bool isEnabled = !_Controller.IsBusy;

			foreach (var control in FieldsToLock)
			{
				if (control is ToolStripItem)
					((ToolStripItem)control).Enabled = isEnabled;
				else if (control is TextBoxBase)
					((TextBoxBase)control).Enabled = isEnabled;
				else if (control is UAddressControl)
					((UAddressControl)control).Enabled = isEnabled;
				else if (control is Control)
					((Control)control).Enabled = isEnabled;
			}

			_ChangeFieldsLock();
		}
		protected void _ChangeFieldsLock()
		{
#if !DESIGN
			bool locked = false;
			if (_FormState.Equals(EFormState.View))
				locked = true;

			foreach (object control in _FieldsToLock)
			{
				if (control is ToolStripItem)
					((ToolStripItem)control).Enabled = !locked && !_Controller.IsBusy;
				else if (control is TextBoxBase)
					((TextBoxBase)control).ReadOnly = locked;
				else if (control is UAddressControl)
					((UAddressControl)control).ReadOnly = locked;
				else if (control is Control)
					((Control)control).Enabled = !locked && !_Controller.IsBusy;
			}
			uEditDefaultToolStrip.RefreshUIState(!_Controller.IsBusy, HasEditPermission);

			// Se está em estado de edição, os controles estão habilitados, por isso, checa
			// as travas condicionais
			if (!locked && !_Controller.IsBusy)
				_RefreshConditionalLocks();
#endif
		}
		#endregion
		#region Loading
		protected override void OnLoad(EventArgs e)
		{
			base.OnLoad(e);

			_LoadData();
		}
		protected void _LoadData()
		{
			_Controller.ClearErrors();
			if (!_Controller.IsBusy)
			{
				_Controller.EnableBusy();
				bw_LoadData.RunWorkerAsync();
			}
        }
        private void bw_LoadData_DoWork(object sender, DoWorkEventArgs e)
        {
			T entity = default(T);
			if (_FormState == EFormState.View)
				entity = _LoadEntity(_Id);

			e.Result = new object[] { entity, _LoadSpecificData() };
        }
        private void bw_LoadData_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
			if (!IsDisposed)
			{
				if (e.Error == null)
				{
					T entity = (T)((object[])e.Result)[0];
					object specificArgs = ((object[])e.Result)[1];

					if (specificArgs != null)
						_FillSpecificData(specificArgs);
					if (entity != null)
					{
						_CurrentEntity = (T)entity;
						_FillEntity(_CurrentEntity);
					}
				}
				else
					_Controller.LoadError(e.Error);
				
				_Controller.DisableBusy();
			}
        }

        protected abstract T _LoadEntity(int id);
        protected abstract void _FillEntity(T entity);
		
		protected virtual object _LoadSpecificData() { return null; }
		protected virtual void _FillSpecificData(object result) { }
        #endregion
        #region Saving
		private void _Save()
		{
			ExceptionsContainer exs = null;
			T entity = default(T);

			_Controller.ClearErrors();
			try
			{
				entity = _BuildEntity();
				exs = _ValidateEntity(entity);
			}
			catch (Exception e)
			{
				if (exs == null)
					exs = new ExceptionsContainer();
				exs.Add(e);
			}

			_Controller.ClearErrors();
			if (exs == null || exs.Count() == 0)
			{
				if (!_Controller.IsBusy)
				{
					_Controller.EnableBusy();
					bw_Save.RunWorkerAsync(entity);
				}
			}
			else
				_Controller.LoadError(exs);
		}
        protected abstract T _BuildEntity();
		protected abstract ExceptionsContainer _ValidateEntity(T entity);
		protected abstract int _SaveEntity(T entity);
        private void bw_Save_DoWork(object sender, DoWorkEventArgs e)
        {
			_Id = _SaveEntity((T)e.Argument);
			e.Result = _CurrentEntity = _LoadEntity(_Id);
        }
        private void bw_Save_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
			if (!IsDisposed)
			{
				_Controller.DisableBusy();
				if (e.Error == null)
				{
					this.DialogResult = DialogResult.OK;
					if (InitialState == EFormState.Edit)
					{
						if (RequestClose != null)
							RequestClose(sender, new EventArgs<DialogResult>(DialogResult));
					}
					else
					{
						_FillEntity((T)e.Result);
						FormState = EFormState.View;
					}

					if (StateModified != null)
						StateModified(this, new EventArgs<int>(_Id));
				}
				else
					_Controller.LoadError(e.Error);
			}
        }
        #endregion
		#region Events Handler
		private void uEditDefaultToolStrip_ExitClicked(object sender, EventArgs e)
		{
			if (RequestClose != null)
				RequestClose(this, new EventArgs<DialogResult>(DialogResult));
		}
		private void uEditDefaultToolStrip_EditClicked(object sender, EventArgs e)
		{
			FormState = EFormState.Edit;
		}
		private void uEditDefaultToolStrip_SaveClicked(object sender, EventArgs e)
		{
			_Controller.ClearErrors();
			_Save();
		}
		private void uEditDefaultToolStrip_CancelClicked(object sender, EventArgs e)
		{
			if (InitialState == EFormState.Edit)
			{
				if (RequestClose != null)
					RequestClose(sender, new EventArgs<DialogResult>(DialogResult));
			}
			else
			{
				FormState = EFormState.View;
				_Controller.ClearErrors();
				_FillEntity(_CurrentEntity);
			}
		}
		private void _Controler_BusyStateChanged(object sender, EventArgs e)
		{
			_RefreshUIState();
			if (!_Controller.IsBusy)
				_Controller.DisplayIdleMessage(_IdleMessage);
			else
				_Controller.DisplayIdleMessage("Aguarde. Carregando...");
		}
		#endregion
        #endregion

		#region IStateModifier Members

		public event EventHandler<EventArgs<int>> StateModified;

		#endregion
	}
}
